#include "preHeader.h"
#include "GuildLeagueHook.h"
#include "MapInstance.h"

GuildLeagueHook::GuildLeagueHook(MapInstance* pMapInstance)
: IMapHook(pMapInstance)
{
	auto& tpPoints = pMapInstance->getGameMap().
		GetTeleportPoints((u32)MapInfo::Type::GuildLeague);
	for (auto i = 0; i < ARRAY_SIZE(m_entryPoints); ++i) {
		auto& tpPoint = tpPoints[i];
		m_entryPoints[i] = {
			tpPoint->x, tpPoint->y, tpPoint->z, tpPoint->o};
	}
}

GuildLeagueHook::~GuildLeagueHook()
{
}

void GuildLeagueHook::InitLuaEnv()
{
	IMapHook::InitLuaEnv();

	auto L = m_pMapInstance->L;
	lua::class_add<GuildLeagueHook>(L, "GuildLeagueHook");
	lua::class_inh<GuildLeagueHook, IMapHook>(L);
	lua::class_def<GuildLeagueHook>(L, "GetTeamSide", &GuildLeagueHook::GetTeamSide);
	lua::class_def<GuildLeagueHook>(L, "TryGetWinGuildId", &GuildLeagueHook::TryGetWinGuildId);
	lua::class_def<GuildLeagueHook>(L, "TryGetWinGuildId4Opening", &GuildLeagueHook::TryGetWinGuildId4Opening);
	lua::class_def<GuildLeagueHook>(L, "JudgeWinGuildId", &GuildLeagueHook::JudgeWinGuildId);

	static const std::string scriptFile = "scripts/Hook/GuildLeague.lua";
	RunScriptFile(L, scriptFile, m_pMapInstance, this);
}

void GuildLeagueHook::InitArgs(const std::string& args)
{
	ConstNetBuffer buffer(args.data(), args.size());
	int64 startTime;
	uint32 prepareTime, durationTime;
	buffer >> startTime >> prepareTime >> durationTime;
	for (int i = 0; i < ARRAY_SIZE(m_guildIds); ++i) {
		buffer >> m_guildIds[i];
	}

	auto t = m_variables.Get<LuaTable>();
	auto funcPlay = t.get<LuaFunc>("Play");
	funcPlay.Call<void>(startTime, prepareTime, durationTime);
}

vector3f1f GuildLeagueHook::GetEntryPoint(
	uint32 gsIdx, const CharTeleportInfo& tpInfo) const
{
	auto teamSide = GetTeamSide(GetGuidFromValue(tpInfo.ownerGuid).UID);
	if (teamSide != teamInvalid) {
		return m_entryPoints[(int)teamSide];
	} else {
		return {FLT_MAX,0,0,0};
	}
}

ArenaTeamSide GuildLeagueHook::GetTeamSide(uint32 guildId) const
{
	auto itr = std::find(m_guildIds, std::end(m_guildIds), guildId);
	if (itr != std::end(m_guildIds)) {
		return (ArenaTeamSide)std::distance(m_guildIds, itr);
	} else {
		return teamInvalid;
	}
}

int64 GuildLeagueHook::TryGetWinGuildId(uint32 loseTeamSide) const
{
	if (loseTeamSide == teamInvalid) {
		return -1;
	}
	for (auto& [_, pPlayer] : m_pMapInstance->GetPlayerStorageMap()) {
		if (pPlayer->GetTeamSide() == loseTeamSide && !pPlayer->IsDead()) {
			return -1;
		}
	}
	return m_guildIds[loseTeamSide != 0 ? 0 : 1];
}

int64 GuildLeagueHook::TryGetWinGuildId4Opening() const
{
	auto& allPlayers = m_pMapInstance->GetPlayerStorageMap();
	if (allPlayers.empty()) {
		return 0;
	}
	int n = 0;
	uint32 attendTeamSides[teamCount];
	for (auto& [_, pPlayer] : allPlayers) {
		auto teamSide = GetTeamSide(pPlayer->GetGuildId());
		if (teamSide == teamInvalid) {
			continue;
		}
		if (IS_INPTR_CONTAIN_VALUE(attendTeamSides, n, teamSide)) {
			continue;
		}
		attendTeamSides[n++] = teamSide;
		if (n >= teamCount) {
			return -1;
		}
	}
	if (n != 0) {
		return m_guildIds[attendTeamSides[0]];
	}
	return 0;
}

uint32 GuildLeagueHook::JudgeWinGuildId() const
{
	return m_guildIds[0];
}
